#pragma once
#include <vector>
#include <queue>
#include "Mutex.hpp"
#include "Thread.hpp"
#include "Cond.hpp"
#include "Log.hpp"

using namespace MutexModule;
using namespace ThreadModule;
using namespace CondModule;
using namespace LogModule;

namespace ThreadPoolModule
{
    class ThreadPoolException : public std::runtime_error
    {
    public:
        explicit ThreadPoolException(const std::string &message)
            : std::runtime_error("ThreadPoolException: " + message) {}
    };

    static const unsigned int default_thread_num = 6;
    static const unsigned int default_capacity = 9;

    template <typename Task>
    class ThreadPool
    {
    private:
        ThreadPool(unsigned int thread_num = default_thread_num)
            : _isrunning(true)
        {
            if (thread_num <= 0)
                throw ThreadPoolException("线程数量过少!");
            for (int i = 1; i <= thread_num; i++)
                _threads.emplace_back("thread-" + std::to_string(i), [this]{ ThreadHandler(); });
        }

        ~ThreadPool()
        {}

        ThreadPool(const ThreadPool<Task>&) = delete;
        ThreadPool<Task>& operator=(const ThreadPool<Task>&) = delete;

        void ThreadHandler()
        {
            while (true)
            {
                Task task;
                {
                    LockGuard lockguard(_queue_mutex);
                    while(_queue.empty() && _isrunning)
                    {
                        _not_empty.wait(_queue_mutex);
                    }
                    if(_queue.empty() && !_isrunning)
                        break;
                    task = _queue.front();
                    _queue.pop();
                }
                task();
            }
            LOG(LogLevel::DEBUG) << "线程[" << Thread::GetMyName() << "]退出...";
        }
        void Start()
        {
            for (auto &thread : _threads)
                thread.Start();
            LOG(LogLevel::DEBUG) << "线程池已启动...";
        }

    public:
        void Stop()
        {
            _isrunning = false;
            _not_empty.broadcast();
            LOG(LogLevel::DEBUG) << "线程池开始停止...";
        }

        void Wait()
        {
            if(_isrunning)
                throw ThreadPoolException("等待前线程池未停止!");
            for (auto &thread : _threads)
                thread.Join();
            LOG(LogLevel::DEBUG) << "等待成功, 线程已全部退出...";
        }

        void PushTask(const Task &task)
        {
            if(!_isrunning)
                throw ThreadPoolException("线程池已停止, 无法继续增加任务!");
            _queue.push(task);
            _not_empty.signal();
        }

        static ThreadPool<Task>& GetInstance()
        {
            static ThreadPool<Task> Instance;
            Instance.Start();
            return Instance;
        }

    private:
        bool _isrunning;
        std::vector<Thread> _threads;
        std::queue<Task> _queue;
        Mutex _queue_mutex;
        Cond _not_empty;
    };
}